package com.xd.core.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Maps;
import com.xd.common.base.CustomRowHeightColWidthHandler;
import com.xd.common.base.RowHeightColWidthModel;
import com.xd.common.config.RabbitConfig;
import com.xd.common.constant.SysConstant;
import com.xd.common.exception.XkdException;
import com.xd.common.properties.PassWordKeyProperties;
import com.xd.common.util.*;
import com.xd.core.api.dto.DelayOfflinePayDto;
import com.xd.core.business.dto.IncomingInfoDto;
import com.xd.core.business.dto.IncomingInfoEnableDto;
import com.xd.core.business.dto.IncomingQuery;
import com.xd.core.business.entity.*;
import com.xd.core.business.mapper.*;
import com.xd.core.business.vo.*;
import com.xd.core.business.service.IIncomingInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xd.core.company.dto.CompanyQuery;
import com.xd.core.company.dto.HomeQueryDto;
import com.xd.core.company.entity.CapitalAgency;
import com.xd.core.company.entity.Company;
import com.xd.core.company.mapper.CapitalAgencyMapper;
import com.xd.core.company.mapper.CompanyMapper;
import com.xd.core.company.vo.IncomingPreview;
import com.xd.core.debt.dto.Review;
import com.xd.core.mission.entity.MissionCenterInfo;
import com.xd.core.mission.mapper.MissionCenterInfoMapper;
import com.xd.core.product.entity.Product;
import com.xd.core.product.entity.ProductCompany;
import com.xd.core.product.mapper.ProductCompanyMapper;
import com.xd.core.product.mapper.ProductMapper;
import com.xd.core.product.vo.ProductRepayment;
import com.xd.core.system.entity.SysUser;
import com.xd.core.system.mapper.SysUserMapper;
import com.xd.core.system.service.ISysUserService;
import io.jsonwebtoken.Claims;
import jodd.io.FileUtil;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 进件信息表 服务实现类
 * </p>
 *
 * @author ZX
 * @since 2025-02-23
 */
@Slf4j
@Service
public class IncomingInfoServiceImpl extends ServiceImpl<IncomingInfoMapper, IncomingInfo> implements IIncomingInfoService {

    @Value("${image.localPathDir}")
    private String localPathDir;
    @Value("${image.exportFile}")
    private String exportFile;
    @Value("${aes.key}")
    private String aesKey;
    @Value("${spring.profiles.active}")
    private String active;
    @Value("${wwyy.appkey}")
    private String apiAppKey;
    @Value("${wwyy.url}")
    private String wwyyUrl;
    @Value("${image.contract}")
    private String contractUrl;
    @Value("${h5link.h5link_incoming}")
    private String h5link_incoming;
    @Value("${h5link.h5link2_contract}")
    private String h5link2_contract;
    @Autowired
    private IncomingCommonLoanMapper incomingCommonLoanMapper;
    @Autowired
    private IncomingUrgentContactMapper incomingUrgentContactMapper;
    @Autowired
    private IncomingInfoMapper incomingInfoMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private CreditMapper creditMapper;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private MissionCenterInfoMapper missionCenterInfoMapper;
    @Autowired
    private IncomingInfoSuppMapper incomingInfoSuppMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private InsuranceCompanyInfoMapper insuranceCompanyInfoMapper;
    @Autowired
    RestTemplateUtil restTemplateUtil;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    private static final String H5_LINK = "H5_LINK:";//H5链接
    @Autowired
    private ProductCompanyMapper productCompanyMapper;

    /**
     三要素认证
     */
    public void threeElementAuthentication(String idCard, String name, String phone) {
        if (!active.equals("prd")) {
            return;
        }
        if (StringUtils.isBlank(idCard) || StringUtils.isBlank(name) || StringUtils.isBlank(phone)) {
           return;
        }
        //用户三要素认证
        String decryptPhone = AESUtil.decrypt(phone, aesKey);
        Map<String, Object> params = new HashMap<>(4);
        params.put("idCard", idCard);
        params.put("name", name);
        params.put("phone", decryptPhone);
        String url = wwyyUrl+apiAppKey;
        ResponseEntity<JSONObject> jsonObjectResponseEntity = restTemplateUtil.postForm(url, params, JSONObject.class);
        JSONObject jsonObject = jsonObjectResponseEntity.getBody();
        if (jsonObject != null) {
            JSONObject showapiResBody = jsonObject.getJSONObject("showapi_res_body");
            String code = showapiResBody.getString("code");
            if (!"0".equals(code)) {
                throw new XkdException("三要素认证失败，"+name+ "："+ showapiResBody.getString("msg"));
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addIncoming(IncomingInfoDto info) {
        Product product = productMapper.selectById(info.getProductId());
        String draftStatus = info.getDraftStatus();//存为草稿
        //验证车贷字段长度
        if ("0".equals(draftStatus) && SysConstant.PRODUCT_TWO.equals(product.getType())){
            validateCarLoanFields(info);
        }
        info.setIncomingId(null);
        SysUser user = SecurityUtil.getLoginUser().getUser();
        validateUserStatus(user);
        List<Integer> productIds = productCompanyMapper.selectProductIds(info.getCompanyId());
        if (!productIds.contains(info.getProductId())){
            throw new XkdException("该公司未配置该产品");
        }
        Company company = companyMapper.selectById(info.getCompanyId());
        //公司是否开启进件开关
        validateCompanyStatus(company, draftStatus);
        Company agency = companyMapper.selectById(info.getIncomingCompanyId());
        validateAgencyStatus(agency, info.getDraftStatus());

        //主借人三要素认证
        threeElementAuthentication(info.getIdCard(), info.getName(), info.getPhone());
        //担保人三要素认证
        threeElementAuthentication(info.getGuarantorIdCard(), info.getGuarantorName(), info.getGuarantorPhone());

        //验证共同借款人不能超过3个
        validateCommonLoaners(info.getIncomingCommonLoans());

        String orderCode = OrderNumUtil.getOrderCodeByCompany(SecurityUtil.getLoginUserId());
        List<IncomingCommonLoan> incomingCommonLoans = info.getIncomingCommonLoans();
        Integer id = user.getId();

        IncomingInfo incomingInfo = BeanUtil.copyProperties(info, IncomingInfo.class);
        incomingInfo.setIncomingUserId(id);
        incomingInfo.setIncomingOrder(orderCode);

        //分配资方进件归属
        String companyType = user.getCompanyType();
        if (!companyType.equals(SysConstant.USER_COMPANY_TYPE_TOW)) {
            allocationUser(incomingInfo, company);
        } else {
            incomingInfo.setManageUserId(id);
        }

        setStatusAndValidateFields(info, incomingInfo, product);

        save(incomingInfo);

        saveSupplementaryInfo(info, incomingInfo);
        saveCommonLoans(incomingCommonLoans, incomingInfo);
        //是否紧急联系人
        if (info.getIsIncomingUrgentContacts().equals("1")) {
            saveUrgentContacts(info.getIncomingUrgentContacts(), incomingInfo);
        }
    }
    /**
     * 验证车贷字段长度
     * @param info 进件信息DTO
     */
    public void validateCarLoanFields(IncomingInfoDto info) {
        // 1. 验证共同借款人字段
        List<IncomingCommonLoan> commonLoans = info.getIncomingCommonLoans();
        if (CollectionUtil.isNotEmpty(commonLoans)) {
            for (IncomingCommonLoan commonLoan : commonLoans) {
                if ("1".equals(commonLoan.getCollateralSwitch())) {
                    // 共同借款人身份证号码
                    String commonIdCard = commonLoan.getIdCard();
                    if (StringUtils.isBlank(commonIdCard) || commonIdCard.length() > 20 || commonIdCard.length() < 12) {
                        throw new XkdException("共同借款人身份证号码长度不能超过20个字符，不能低于12个字符");
                    }
                    // 共同借款人车辆产权所有人姓名
                    String commonCarOwners = commonLoan.getCarOwners();
                    if (StringUtils.isBlank(commonCarOwners) || commonCarOwners.length() > 20 || commonCarOwners.length() < 2) {
                        throw new XkdException("共同借款人车辆产权所有人姓名长度不能超过20个字符，不能低于2个字符");
                    }
                    // 共同借款人车辆号牌
                    String commonCarNo = commonLoan.getCarNo();
                    if (StringUtils.isBlank(commonCarNo) || commonCarNo.length() > 20) {
                        throw new XkdException("共同借款人车辆号牌长度不能超过20个字符，不能低于1个字符");
                    }
                    // 共同借款人车辆识别码
                    String commonCarCode = commonLoan.getCarCode();
                    if (StringUtils.isBlank(commonCarCode) || commonCarCode.length() > 30) {
                        throw new XkdException("共同借款人车辆识别码长度不能超过30个字符，不能低于1个字符");
                    }
                    // 共同借款人车辆发动机号码
                    String commonCarEngineNo = commonLoan.getCarEngineNo();
                    if (StringUtils.isBlank(commonCarEngineNo) || commonCarEngineNo.length() > 30) {
                        throw new XkdException("共同借款人车辆发动机号码长度不能超过30个字符，不能低于1个字符");
                    }
                }
            }
        }

        // 2. 验证主借款人字段
        // 主借款人身份证号码
        String mainIdCard = info.getIdCard();
        if (StringUtils.isBlank(mainIdCard) || mainIdCard.length() > 20 || mainIdCard.length() < 12) {
            throw new XkdException("身份证号码长度不能超过20个字符，不能低于12个字符");
        }
        // 主借款人车辆产权所有人姓名
        String mainCarOwners = info.getCarOwners();
        if (StringUtils.isBlank(mainCarOwners) || mainCarOwners.length() > 20 || mainCarOwners.length() < 2) {
            throw new XkdException("车辆产权所有人姓名长度不能超过20个字符，不能低于2个字符");
        }
        // 主借款人车辆号牌
        String mainCarNo = info.getCarNo();
        if (StringUtils.isBlank(mainCarNo) || mainCarNo.length() > 20) {
            throw new XkdException("车辆号牌长度不能超过20个字符，不能低于1个字符");
        }
        // 主借款人车辆识别码
        String mainCarCode = info.getCarCode();
        if (StringUtils.isBlank(mainCarCode) || mainCarCode.length() > 30) {
            throw new XkdException("车辆识别码长度不能超过30个字符，不能低于1个字符");
        }
        // 主借款人车辆发动机号码
        String mainCarEngineNo = info.getCarEngineNo();
        if (StringUtils.isBlank(mainCarEngineNo) || mainCarEngineNo.length() > 30) {
            throw new XkdException("车辆发动机号码长度不能超过30个字符，不能低于1个字符");
        }
    }

    private void AutoCheckIncoming(Review msg, int delayMillis) {
        log.info("发送自动审核订单延迟消息");
        rabbitTemplate.convertAndSend(
                RabbitConfig.DELAY_EXCHANGE,
                RabbitConfig.DELAY_ROUTING_KEY_CHECKINCOMING,
                msg,
                message -> {
                    message.getMessageProperties().setDelay(delayMillis);
                    return message;
                });
    }

    private void validateUserStatus(SysUser user) {
        if (SysConstant.USER_DISABLE.equals(user.getStatus())) {
            throw new XkdException("账号状态已禁用");
        }
    }

    private void validateCompanyStatus(Company company, String draftStatus) {
        if (SysConstant.INCOMING_STATUS_DISABLE.equals(company.getIncomingStatus()) && "0".equals(draftStatus)) {
            throw new XkdException("公司未开启进件开关");
        }
    }

    private void validateAgencyStatus(Company agency, String draftStatus) {
        if (ObjectUtil.isNotEmpty(agency) && SysConstant.COMPANY_TYPE_TOW.equals(agency.getCompanyType())) {
            if (SysConstant.INCOMING_STATUS_DISABLE.equals(agency.getIncomingStatus()) && "0".equals(draftStatus)) {
                throw new XkdException("公司未开启进件开关");
            }
        }
    }

    private void validateCommonLoaners(List<IncomingCommonLoan> incomingCommonLoans) {
        if (CollectionUtil.isNotEmpty(incomingCommonLoans) && incomingCommonLoans.size() > 3) {
            throw new XkdException("共同借款人不能超过三个");
        }
    }

    private void setStatusAndValidateFields(IncomingInfoDto info, IncomingInfo incomingInfo, Product product) {
        if ("0".equals(info.getDraftStatus())) {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_TWO);
            validateMortgageFields(info, product);
            // 确保锁的释放在事务提交之后
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {//事务成功后执行
                    try {
                        log.info("执行自动审核");
                        //自动审核进件状态
                        Review review = new Review();
                        review.setId(incomingInfo.getIncomingId());
                        review.setStatus("0");
                        AutoCheckIncoming(review, 2000);
                    } catch (Exception e) {
                        throw new XkdException("审核失败");
                    }
                }
            });

        } else {
            XkdUtil.checkNonNullProperties(info, "idCard");
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_ONE);
        }
    }

    /**
     * 验证房车信息是否填完
     *
     * @param info
     * @param product
     */
    private void validateMortgageFields(IncomingInfoDto info, Product product) {
        if (product.getType().equals(SysConstant.PRODUCT_TWO)) {
            XkdUtil.checkNonNullProperties(info, "carType", "carOwners", "guaAmount", "carCert", "carUseType", "carSurtaxCert", "carNo", "carBrand", "carEngineNo", "carCode", "carValuation");
        }
        if (product.getType().equals(SysConstant.PRODUCT_THREE) || (product.getType().equals(SysConstant.PRODUCT_FOUR) && info.getIsJydMortgage().equals("1"))) {
            XkdUtil.checkNonNullProperties(info, "houseStatus", "houseType", "houseOwners", "houseNo", "houseUseType", "houseAddress", "houseBuildingArea", "houseLandArea", "houseCommunalForm", "houseAge", "houseDeadTime", "houseValuation", "houseCert");
        }
    }

    private void saveSupplementaryInfo(IncomingInfoDto info, IncomingInfo incomingInfo) {
        IncomingInfoSupp incomingInfoSupp = BeanUtil.copyProperties(info, IncomingInfoSupp.class);
        incomingInfoSupp.setIncomingId(incomingInfo.getIncomingId());
        incomingInfoSuppMapper.insert(incomingInfoSupp);
    }

    private void saveCommonLoans(List<IncomingCommonLoan> incomingCommonLoans, IncomingInfo incomingInfo) {
        if (CollectionUtil.isNotEmpty(incomingCommonLoans)) {
            for (IncomingCommonLoan loan : incomingCommonLoans) {
                loan.setIncomingId(incomingInfo.getIncomingId());
                //用户三要素认证
                threeElementAuthentication(loan.getIdCard(), loan.getName(), loan.getPhone());
            }
            incomingCommonLoanMapper.batchInsert(incomingCommonLoans);
        }
    }

    private void saveUrgentContacts(List<IncomingUrgentContact> incomingUrgentContacts, IncomingInfo incomingInfo) {
        if (CollectionUtil.isNotEmpty(incomingUrgentContacts)) {
            for (IncomingUrgentContact contact : incomingUrgentContacts) {
                contact.setIncomingId(incomingInfo.getIncomingId());
            }
            incomingUrgentContactMapper.batchInsert(incomingUrgentContacts);
        }
    }


    /**
     * 代理,平台进件自动分配到资方账户
     *
     * @param info    进件信息
     * @param company 公司
     */
    private void allocationUser(IncomingInfo info, Company company) {
        //获取资方分配员工
        Integer a2 = company.getAllocationUserId();
        Integer companyId = company.getId();
        //如果资方没有员工,则分配到主账号
        LambdaQueryWrapper<SysUser> wrapper1 = new LambdaQueryWrapper<SysUser>().eq(SysUser::getCompanyId, companyId).eq(SysUser::getStatus, SysConstant.USER_ENABLE);
        Integer count = sysUserMapper.selectCount(wrapper1);
        Integer nextUserId = null;
        if (1 == count) {//只有主账号
            SysUser sysUser = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getCompanyId, companyId)
                    .eq(SysUser::getUserType, SysConstant.USER_TYPE_P));
            nextUserId = sysUser.getId();
        } else {//有员工
            if (a2 != null) {//已经分配过员工
                //获取下一位分配员工id
                nextUserId = sysUserMapper.getUserOfAllocation(a2, companyId, SysConstant.USER_TYPE_B);
                if (nextUserId == null) {//代表已分到最后一位
                    nextUserId = sysUserMapper.getUserOfAllocation(null, companyId, SysConstant.USER_TYPE_B);
                }

            } else {
                nextUserId = sysUserMapper.getUserOfAllocation(null, companyId, SysConstant.USER_TYPE_B);
            }
        }
        //修改公司表已分配的员工id
        Company c = new Company();
        c.setId(company.getId());
        c.setAllocationUserId(nextUserId);
        companyMapper.updateById(c);
        info.setManageUserId(nextUserId);
    }


    @Override
    public IncomingInfoVo getDetail(Integer id) {
        IncomingInfoVo detail = incomingInfoMapper.getDetail(id);

        LambdaQueryWrapper<IncomingCommonLoan> queryWrapper = new LambdaQueryWrapper<IncomingCommonLoan>()
                .eq(IncomingCommonLoan::getIncomingId, id);
        List<IncomingCommonLoan> commonLoans = incomingCommonLoanMapper.selectList(queryWrapper);
        detail.setIncomingCommonLoans(commonLoans);
        return detail;
    }


    @Override
    public List<IncomingInfoPageVo> getIncomingListForExport(IncomingQuery query) {
        String companyType = SecurityUtil.getLoginUser().getUser().getCompanyType();
        Integer companyId = query.getCompanyId();
        List<Integer> userIds = null;
        if (!companyType.equals(SysConstant.USER_COMPANY_TYPE_ONE)) {
            companyId = SecurityUtil.getLoginCompanyId();
            userIds = iSysUserService.getUserIdsByGroup();
        }
        return incomingInfoMapper.selectIncomingListAll(query, userIds, companyId, companyType);
    }


    @Override
    public Page<IncomingInfoPageVo> incomingList(IncomingQuery query) {
        String companyType = SecurityUtil.getLoginUser().getUser().getCompanyType();
        Integer companyId = query.getCompanyId();
        List<Integer> userIds = null;
        if (!companyType.equals(SysConstant.USER_COMPANY_TYPE_ONE) && !companyType.equals(SysConstant.USER_COMPANY_TYPE_FOUR)) {//不是平台和集团
            companyId = SecurityUtil.getLoginCompanyId();
            userIds = iSysUserService.getUserIdsByGroup();
        }
        //获取用户数据权限
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return (Page<IncomingInfoPageVo>) incomingInfoMapper.selectIncomingList(query, userIds, companyId, companyType);
    }

    @Override
    public void updateStatus(IncomingInfoEnableDto incomingInfoEnableDto) {
        String companyType = SecurityUtil.getLoginUser().getUser().getCompanyType();
        if (companyType.equals(SysConstant.USER_COMPANY_TYPE_ONE)) {//不是平台
            incomingInfoMapper.updateEnable(incomingInfoEnableDto);
        } else {
            throw new XkdException("非平台用户不能操作");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateIncoming(IncomingInfoDto infoDto) {
        SysUser user = SecurityUtil.getLoginUser().getUser();
        validateUserStatus(user);
        Product product = productMapper.selectById(infoDto.getProductId());
        String draftStatus = infoDto.getDraftStatus();//存为草稿
        List<Integer> productIds = productCompanyMapper.selectProductIds(infoDto.getCompanyId());
        if (!productIds.contains(infoDto.getProductId())){
            throw new XkdException("该公司未配置该产品");
        }
        //验证车贷字段长度
        if ("0".equals(draftStatus) && SysConstant.PRODUCT_TWO.equals(product.getType())){
            validateCarLoanFields(infoDto);
        }
        Company company = companyMapper.selectById(infoDto.getCompanyId());
        validateCompanyStatus(company, infoDto.getDraftStatus());

        Company agency = companyMapper.selectById(infoDto.getIncomingCompanyId());
        validateAgencyStatus(agency, infoDto.getDraftStatus());

        Integer incomingId = infoDto.getIncomingId();
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);

        validateCommonLoaners(infoDto.getIncomingCommonLoans());

        List<IncomingCommonLoan> incomingCommonLoans = infoDto.getIncomingCommonLoans();
        List<IncomingUrgentContact> incomingUrgentContacts = infoDto.getIncomingUrgentContacts();

        IncomingInfoSupp incomingInfoSupp = BeanUtil.copyProperties(infoDto, IncomingInfoSupp.class);
        incomingInfoSuppMapper.updateById(incomingInfoSupp);

        //删除原来的共同贷款人,再新增
        incomingCommonLoanMapper.deleteById(infoDto.getIncomingId());
        if (CollectionUtil.isNotEmpty(incomingCommonLoans)) {
            incomingCommonLoanMapper.batchInsert(incomingCommonLoans);
        }

        //修改紧急联系人
        incomingUrgentContactMapper.deleteById(infoDto.getIncomingId());
        if (CollectionUtil.isNotEmpty(incomingUrgentContacts)) {
            incomingUrgentContactMapper.batchInsert(incomingUrgentContacts);
        }
        BeanUtil.copyProperties(infoDto, incomingInfo, "incomingCompanyId");


        //存为草稿
        if ("0".equals(infoDto.getDraftStatus())) {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_TWO);
            //如果选择需要抵押的贷款产品,检查是否填入补充信息
            if (product.getType().equals(SysConstant.PRODUCT_TWO)) {
                XkdUtil.checkNonNullProperties(infoDto, "carType", "carOwners", "guaAmount", "carCert", "carUseType", "carSurtaxCert", "carNo", "carBrand", "carEngineNo", "carCode", "carValuation");
            }
            if (product.getType().equals(SysConstant.PRODUCT_THREE) || (product.getType().equals(SysConstant.PRODUCT_FOUR) && infoDto.getIsJydMortgage().equals("1"))) {
                XkdUtil.checkNonNullProperties(infoDto, "houseStatus", "houseType", "houseOwners", "houseNo", "houseUseType", "houseAddress", "houseBuildingArea", "houseLandArea", "houseCommunalForm", "houseAge", "houseDeadTime", "houseValuation", "houseCert");
            }
        } else {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_ONE);
        }
        //自动审核进件状态
        Review review = new Review();
        review.setId(incomingInfo.getIncomingId());
        review.setStatus("0");
        AutoCheckIncoming(review, 2000);
        updateById(incomingInfo);
    }

    @Override
    public void exportIncomingInfoList(IncomingQuery query, Integer id) {
        String name = "进件excel文件" + UUID.randomUUID().toString().replace("-", "");
        Integer companyId = SecurityUtil.getLoginCompanyId();
        FileOutputStream fileOutputStream = null;
        MissionCenterInfo missionCenterInfo = new MissionCenterInfo();
        missionCenterInfo.setId(id);
        missionCenterInfo.setFileName(name + ".xlsx");

        String filePath = localPathDir + exportFile + "/" + companyId;
        File dirFile = new File(filePath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }

        try {
            List<RowHeightColWidthModel> rowHeightColWidthList = new ArrayList<>();
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 0, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 1, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 2, 10));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 3, 15));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 4, 10));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 5, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 6, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 7, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 8, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 9, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 10, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 11, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 12, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 13, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 14, 20));
            File file = new File(filePath + "/" + name + ".xlsx");
            fileOutputStream = new FileOutputStream(file);

            ExcelWriter write = EasyExcel.write(fileOutputStream, IncomingInfoPageVo.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(name).registerWriteHandler(new CustomRowHeightColWidthHandler(rowHeightColWidthList)).build();
            List<IncomingInfoPageVo> list = getIncomingListForExport(query);
            for (IncomingInfoPageVo customerInfoVo : list) {
                String decryptPhone = AESUtil.decrypt(customerInfoVo.getPhone(), aesKey);
                customerInfoVo.setPhone(decryptPhone);
                String isEnable = customerInfoVo.getIsEnable();
                customerInfoVo.setIsEnable(isEnable.equals("1") ? "停用" : "启用");
            }
            write.write(list, writeSheet);
            write.finish();
            fileOutputStream.flush();
            //修改文件状态 导出成功
            missionCenterInfo.setFileStatus(SysConstant.YSZT_FILE_STATUS_TOW);
            missionCenterInfo.setFileUrl(exportFile + "/" + companyId + "/" + name + ".xlsx");
            missionCenterInfoMapper.updateById(missionCenterInfo);
        } catch (Exception e) {
            //修改文件状态 导出失败
            missionCenterInfo.setFileStatus(SysConstant.YSZT_FILE_STATUS_THREE);
            missionCenterInfoMapper.updateById(missionCenterInfo);
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public MortgageVo getMortgageDetail(Integer id) {
        return incomingInfoMapper.getMortgageDetail(id);
    }

    @Override
    public IncomingPreview getIncomingPreview(HomeQueryDto query) {
        Integer companyId = SecurityUtil.getLoginCompanyId();
        String companyType = SecurityUtil.getLoginCompany().getCompanyType();
        if (StringUtils.isEmpty(query.getStartTime()) && StringUtils.isEmpty(query.getEndTime())) {
            LocalDate today = LocalDate.now();
            LocalDate oneMonthAgo = today.minusMonths(1);

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            query.setStartTime(oneMonthAgo.format(formatter));
            query.setEndTime(today.format(formatter));

        }
        Integer incomingTotal = incomingInfoMapper.getIncomingPreview1(query, companyId, companyType);
        Integer agencyIncomingCounts = incomingInfoMapper.getIncomingPreview2(query, companyId, companyType);
        Integer platformIncomingCounts = incomingInfoMapper.getIncomingPreview3(query, companyId, companyType);
        Integer capitalIncomingCounts = incomingInfoMapper.getIncomingPreview4(query, companyId, companyType);
        return new IncomingPreview(incomingTotal, agencyIncomingCounts, platformIncomingCounts, capitalIncomingCounts);
    }

    @Override
    public void platformReview(Review review) {
        if (review.getFlag().equals("1")) {
            // 检查是否为平台用户
            Integer companyId = SecurityUtil.getLoginCompanyId();
            if (companyId != 0) {
                throw new XkdException("非平台用户不能审核");
            }
        }
        IncomingInfo info = getById(review.getId());
        if (!info.getStatus().equals(SysConstant.BUSINESS_STATUS_TWO)) {
            return;
        }
        //审核失败
        if ("1".equals(review.getStatus())) {
            updateIncomingInfoStatus(review.getId(), null, SysConstant.BUSINESS_STATUS_ONE);
            return;
        }

        // 检查用户是否签署了个人信息使用授权书
//        String personalInfoStatus = iIncomingInfoService.getById(review.getId()).getPersonalInfoStatus();
//        if ("0".equals(personalInfoStatus)){
//            throw new XkdException("用户未签署个人信息使用授权书");
//        }

        //生产刘总说的临时授权书
        String contractNo = OrderNumUtil.getContractNo();
        String filePath = contractUrl + "/" + info.getCompanyId() + "/" + contractNo + ".pdf";
        String fileUrl = localPathDir + filePath;//文件下载路径
        Contract c = new Contract();
        //第一次签约
        //保存签约合同信息
        c.setIncomingId(info.getIncomingId());
        c.setContractNo(contractNo);
        c.setType(SysConstant.CONTRACT_TYPE_ONE);
        c.setStatus(SysConstant.CONTRACT_DO);
        c.setStartTime(new Date());
        c.setContractTime(new Date());
        c.setContractName("个人信息授权书");
        c.setCompanyId(info.getCompanyId());
        c.setContract(filePath);
        contractMapper.insert(c);

        Map<String, Object> map = Maps.newHashMap();
        map.put("name", info.getName());
        map.put("time", new SimpleDateFormat("yyyy年MM月dd日").format(new Date()));
        map.put("idcard", info.getIdCard());
        PdfUtil.Pdf2(map, "/个人信息授权使用书模板.pdf", fileUrl);
        updateIncomingInfoStatus(review.getId(), "1", SysConstant.BUSINESS_STATUS_THREE);
    }

    @Override
    public IncomingInfoVo getReIncoming(Integer id) throws IOException {
        IncomingInfoVo detail = incomingInfoMapper.getDetail(id);
        IncomingInfoSupp incomingInfoSupp = incomingInfoSuppMapper.selectById(id);
        LambdaQueryWrapper<IncomingCommonLoan> queryWrapper = new LambdaQueryWrapper<IncomingCommonLoan>()
                .eq(IncomingCommonLoan::getIncomingId, id);
        List<IncomingCommonLoan> commonLoans = incomingCommonLoanMapper.selectList(queryWrapper);

        //复制所有图片
        String houseCertMaster = incomingInfoSupp.getHouseCert();
        String carCertMaster = incomingInfoSupp.getCarCert();
        String carSurtaxCertMaster = incomingInfoSupp.getCarSurtaxCert();
        String idCardFrontUrl = detail.getIdCardFrontUrl();
        String idCardReverseUrl = detail.getIdCardReverseUrl();
        String guarantorIdCardFront = detail.getGuarantorIdCardFront();
        String guarantorIdCardReverse = detail.getGuarantorIdCardReverse();
        String annex = detail.getAnnex();

        if (StringUtils.isNotBlank(annex)) {
            List<String> oldFiles = Arrays.asList(annex.split(","));
            List<String> newFiles = new ArrayList<>(); // 创建一个新列表存储处理后的文件名

            for (String oldFile : oldFiles) {
                String newFile = copyFilesWithoutOverwrite(oldFile);
                newFiles.add(newFile); // 将新文件名添加到新列表
            }

            String newAnnex = newFiles.stream().collect(Collectors.joining(","));
            detail.setAnnex(newAnnex);
        }
        for (IncomingCommonLoan commonLoan : commonLoans) {
            String carSurtaxCert = commonLoan.getCarSurtaxCert();
            String carCert = commonLoan.getCarCert();
            String houseCert = commonLoan.getHouseCert();
            String idCardFrontUrl1 = commonLoan.getIdCardFrontUrl();
            String idCardReverseUrl1 = commonLoan.getIdCardReverseUrl();
            commonLoan.setIdCardFrontUrl(copyFilesWithoutOverwrite(idCardFrontUrl1));
            commonLoan.setIdCardReverseUrl(copyFilesWithoutOverwrite(idCardReverseUrl1));
            commonLoan.setCarSurtaxCert(copyFilesWithoutOverwrite(carSurtaxCert));
            commonLoan.setCarCert(copyFilesWithoutOverwrite(carCert));
            commonLoan.setHouseCert(copyFilesWithoutOverwrite(houseCert));
        }

        detail.setIncomingCommonLoans(commonLoans);
        String fundProve = detail.getFundProve();
        String socialProve = detail.getSocialProve();
        String houseCert = detail.getHouseCert();

        String carCert = detail.getCarCert();
        String carSurtaxCert = detail.getCarSurtaxCert();

        detail.setCarCert(carCertMaster);
        detail.setCarCertUrl(carSurtaxCertMaster);
        detail.setHouseCert(copyFilesWithoutOverwrite(houseCertMaster));
        detail.setFundProve(copyFilesWithoutOverwrite(fundProve));
        detail.setSocialProve(copyFilesWithoutOverwrite(socialProve));
        detail.setHouseCertUrl(copyFilesWithoutOverwrite(houseCert));
        detail.setCarCert(copyFilesWithoutOverwrite(carCert));
        detail.setCarSurtaxCert(copyFilesWithoutOverwrite(carSurtaxCert));
        detail.setIdCardFrontUrl(copyFilesWithoutOverwrite(idCardFrontUrl));
        detail.setIdCardReverseUrl(copyFilesWithoutOverwrite(idCardReverseUrl));
        detail.setGuarantorIdCardFront(copyFilesWithoutOverwrite(guarantorIdCardFront));
        detail.setGuarantorIdCardReverse(copyFilesWithoutOverwrite(guarantorIdCardReverse));
        return detail;
    }

    @Override
    public String addSlipIncoming(IncomingInfoDto info) {
        SysUser user = SecurityUtil.getLoginUser().getUser();
        validateUserStatus(user);
        if (info.getPrincipalType().equals(SysConstant.PRINCIPAL_TYPE_ZERO)) {
            //验证投保公司是否启用
            Integer insuranceCompanyId = info.getInsuranceCompanyId();
            InsuranceCompanyInfo insuranceCompanyInfo = insuranceCompanyInfoMapper.selectById(insuranceCompanyId);
            if (insuranceCompanyInfo == null || insuranceCompanyInfo.getIsEnable() == 0) {
                throw new XkdException("投保公司未启用");
            }
        }

        Company company = companyMapper.selectById(info.getCompanyId());
        //公司是否开启进件开关
        validateCompanyStatus(company, info.getDraftStatus());
        Company agency = companyMapper.selectById(info.getIncomingCompanyId());
        validateAgencyStatus(agency, info.getDraftStatus());

        String orderCode = OrderNumUtil.getOrderCodeByCompany(SecurityUtil.getLoginUserId());
        Integer id = user.getId();

        IncomingInfo incomingInfo = BeanUtil.copyProperties(info, IncomingInfo.class);
        incomingInfo.setIncomingUserId(id);
        incomingInfo.setIncomingOrder(orderCode);

        //分配资方进件归属
        String companyType = user.getCompanyType();
        if (!companyType.equals(SysConstant.USER_COMPANY_TYPE_TOW)) {
            allocationUser(incomingInfo, company);
        } else {
            incomingInfo.setManageUserId(id);
        }
        if ("0".equals(info.getDraftStatus())) {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_TWO);
        } else {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_ONE);
        }
        save(incomingInfo);
        return getIncomingUrl(incomingInfo.getIncomingId(), SysConstant.INCOMING_URL_TYPE_ONE,null);
    }

    @Override
    public Page<InsuranceIncomingInfoPageVo> insuranceIncomingList(IncomingQuery query) {
        String companyType = SecurityUtil.getLoginUser().getUser().getCompanyType();
        Integer companyId = query.getCompanyId();
        List<Integer> userIds = null;
        if (!companyType.equals(SysConstant.USER_COMPANY_TYPE_ONE) && !companyType.equals(SysConstant.USER_COMPANY_TYPE_FOUR)) {//不是平台和集团
            companyId = SecurityUtil.getLoginCompanyId();
            userIds = iSysUserService.getUserIdsByGroup();
        }
        //获取用户数据权限
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return (Page<InsuranceIncomingInfoPageVo>) incomingInfoMapper.insuranceIncomingList(query, userIds, companyId, companyType);
    }

    @Override
    public void updateSlipIncoming(IncomingInfoDto info) {
        SysUser user = SecurityUtil.getLoginUser().getUser();
        validateUserStatus(user);
        if (info.getPrincipalType().equals(SysConstant.PRINCIPAL_TYPE_ZERO)) {
            //验证投保公司是否启用
            Integer insuranceCompanyId = info.getInsuranceCompanyId();
            InsuranceCompanyInfo insuranceCompanyInfo = insuranceCompanyInfoMapper.selectById(insuranceCompanyId);
            if (insuranceCompanyInfo == null || insuranceCompanyInfo.getIsEnable() == 0) {
                throw new XkdException("投保公司未启用");
            }
        }

        Company company = companyMapper.selectById(info.getCompanyId());
        //公司是否开启进件开关
        validateCompanyStatus(company, info.getDraftStatus());
        Company agency = companyMapper.selectById(info.getIncomingCompanyId());
        validateAgencyStatus(agency, info.getDraftStatus());

        String orderCode = OrderNumUtil.getOrderCodeByCompany(SecurityUtil.getLoginUserId());
        Integer id = user.getId();

        IncomingInfo incomingInfo = BeanUtil.copyProperties(info, IncomingInfo.class);
        incomingInfo.setIncomingUserId(id);
        incomingInfo.setIncomingOrder(orderCode);

        //分配资方进件归属
        String companyType = user.getCompanyType();
        if (!companyType.equals(SysConstant.USER_COMPANY_TYPE_TOW)) {
            allocationUser(incomingInfo, company);
        } else {
            incomingInfo.setManageUserId(id);
        }
        if ("0".equals(info.getDraftStatus())) {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_TWO);
        } else {
            incomingInfo.setStatus(SysConstant.BUSINESS_STATUS_ONE);
        }
        updateById(incomingInfo);
        getIncomingUrl(incomingInfo.getIncomingId(), SysConstant.INCOMING_URL_TYPE_ONE,null);
    }

    @Override
    public InsuranceIncomingCreditInfo getSlipBusinessDetail(Integer incomingId) {
        return incomingInfoMapper.getSlipBusinessDetail(incomingId);
    }

    @Override
    public CreditInsuranceVo getSlipBusinessInsuranceDetail(Integer incomingId) {
        return creditMapper.getSlipBusinessInsuranceDetail(incomingId);
    }


    public String copyFilesWithoutOverwrite(String fileName) throws IOException {
        if (StringUtils.isBlank(fileName)) {
            return null;
        }
        fileName = localPathDir + fileName;
        File file = new File(fileName);

        String fileType = fileName.substring(fileName.lastIndexOf("."));
        fileName = fileName.substring(0, fileName.lastIndexOf(".")) + "-" + OrderNumUtil.getDateTime() + fileType;
        File file2 = new File(fileName);
        FileUtil.copy(file, file2);
        return fileName.substring(fileName.indexOf("xdImages") + 8);
    }


    private void updateIncomingInfoStatus(Integer incomingId, String examineStatus, String businessStatus) {
        UpdateWrapper<IncomingInfo> updateWrapper = Wrappers.<IncomingInfo>update()
                .set(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(examineStatus), "examine_status", examineStatus)
                .set("status", businessStatus)
                .set("update_time", new Date())
                .eq("incoming_id", incomingId);
        update(updateWrapper);

    }

    /*
     * 生成二维码链接
     * type:1-进件认证，2-签约
     * payPass:1-通道一，2-通道二
     * */
    public String getIncomingUrl(Integer incomingId, String type,String payPass) {
        HashMap<String, Object> jwtToken = new HashMap();
        jwtToken.put("incomingId", incomingId);
        jwtToken.put("payPass", payPass);
        String jsonString = JSONObject.toJSONString(jwtToken);
        long ttlminute = 60 * 60;
        String token = JwtUtil.createJWT(jsonString, ttlminute*1000L);//一个小时失效
        redisTemplate.opsForValue().set(H5_LINK + token, "1", ttlminute, TimeUnit.SECONDS);//存入redis
        if (type.equals("1")) {
            log.info("生成进件认证链接：{}", h5link_incoming + "?token=" + token);
            return h5link_incoming + "?token=" + token;
        } else if (type.equals("2")) {
            log.info("生成签约链接：{}", h5link2_contract + "?token=" + token);
            return h5link2_contract + "?token=" + token;
        }
        return null;
    }


}